//
// Created by csy on 2023/5/30.
//

#include <sys/timerfd.h>
#include <cstring>

#include "timer.h"
#include "../common/log.h"
#include "../common/util.h"

namespace rocket {
  Timer::Timer() : FdEvent() {
    _fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
    LOG_DEBUG("createn timer -- fd : %d", _fd);
    // 设置定时器事件属性
    listen(FdEvent::IN_EVENT, [this] { onTimer(); });
  }

  void Timer::addTimerEvent(const TimerEvent::ptr& event) {
    bool is_reset_timerfd = false;
    ScopeMutex<Mutex> lock(_mutex);
    if (_pending_events.empty()) {
      is_reset_timerfd = true;
    } else {
      auto it = _pending_events.begin();
      if ((*it)->getArriveTime() < event->getArriveTime()) {
        is_reset_timerfd = true;
      }
    }
    _pending_events.insert(event);
    if (is_reset_timerfd) {
      lock.unlock();
      resetArriveTime();
    }
  }

  void Timer::resetArriveTime() {
    ScopeMutex<Mutex> lock(_mutex);

    if (_pending_events.empty()) {
      return ;
    }

    int64_t now = getNowMs();
    int64_t interval = 100;
    auto it = _pending_events.begin();
    if ((*it)->getArriveTime() > now) {  // 超时时间还没到
      interval = (*it)->getArriveTime() - now;
    }

    timespec ts{};
    memset(&ts, 0, sizeof ts);
    ts.tv_sec = interval / 1000;
    ts.tv_nsec = (interval % 1000) * 1000000;

    itimerspec value{};
    memset(&value, 0, sizeof value);
    value.it_value = ts;

    int rt = timerfd_settime(_fd, 0, &value, nullptr);
    if (rt != 0) {
      LOG_ERROR("timerfd_settime error : %s", strerror(errno));
    }
    LOG_DEBUG("reset time success -- [%lld]", now + interval);
  }

  void Timer::onTimer() {
    LOG_DEBUG("call onTimer");
    char buf[8];
    // 非阻塞，得一次把数据读完
    while(!(read(_fd, buf, 8) == -1 && errno == EAGAIN));
    // 执行定时任务
    int64_t now = getNowMs();

    std::vector<TimerEvent::ptr> record_events;
    std::vector<std::function<void()>> tasks;

    ScopeMutex<Mutex> lock(_mutex);
    auto task = _pending_events.begin();
    for (; task != _pending_events.end(); task++) {
      if ((*task)->getArriveTime() <= now) {
        if (!(*task)->isCancled()) {
          record_events.push_back((*task));
          tasks.push_back((*task)->getCallBack());
        }
      } else {
        break;
      }
    }
    _pending_events.erase(_pending_events.begin(), task);
    lock.unlock();

    for (const auto& time_event : record_events) {
      if (time_event->isRepeated()) {
        time_event->resetArriveTime();
        addTimerEvent(time_event);
      }
    }
    resetArriveTime();

    for (const auto& func : tasks) {
      func();
    }
  }

  void Timer::deleteTimerEvent(const TimerEvent::ptr& event) {
    ScopeMutex<Mutex> lock(_mutex);

    event->setCancled(true);
    _pending_events.erase(event);
    LOG_DEBUG("success delete a time_event");
  }

}